package com.lv.drawable.drawable

import android.content.res.ColorStateList
import android.content.res.Resources
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.util.TypedValue

enum class Shape {
    RECTANGLE,
    OVAL,
    LINE,
    RING
}

enum class GradientType {
    LINEAR,
    RADIAL,
    SWEEP
}

class ShapeBuilder(private val shape: Shape) {

    private var sizeBuilder = SizeBuilder()
    private var strokeBuilder = StrokeBuilder()
    private var cornersBuilder = CornersBuilder()
    private var paddingBuilder = PaddingBuilder()
    private var gradientBuilder = GradientBuilder()

    var solid: ColorStateList? = null
    var orientation = GradientDrawable.Orientation.TOP_BOTTOM

    fun solid(color: Int) = apply {
        solid = ColorStateList.valueOf(color)
    }

    fun corner(builder: CornersBuilder.() -> Unit) = apply {
        cornersBuilder.builder()
    }

    fun corner(corners: Float) = apply {
        cornersBuilder.topLeft = corners.dp
        cornersBuilder.topRight = corners.dp
        cornersBuilder.bottomLeft = corners.dp
        cornersBuilder.bottomRight = corners.dp
    }

    fun padding(builder: PaddingBuilder.() -> Unit) = apply {
        paddingBuilder.builder()
    }

    fun padding(padding: Int) = apply {
        paddingBuilder.left = padding.dp
        paddingBuilder.right = padding.dp
        paddingBuilder.top = padding.dp
        paddingBuilder.bottom = padding.dp
    }

    fun stroke(builder: StrokeBuilder.() -> Unit) = apply {
        strokeBuilder.builder()
    }

    fun size(w: Int, h: Int) = apply {
        sizeBuilder.width = w.dp
        sizeBuilder.height = h.dp
    }

    fun gradient(builder: GradientBuilder.() -> Unit) = apply {
        gradientBuilder.builder()
    }

    fun build(): GradientDrawable {
        val drawable = GradientDrawable()
        drawable.orientation = orientation
        val colors = gradientBuilder.colors
        if (colors.size < 2) {
            drawable.color = solid
        } else {
            drawable.colors = colors
        }
        drawable.shape = shape.ordinal
        drawable.useLevel = gradientBuilder.userLevel
        drawable.gradientType = gradientBuilder.type.ordinal
        drawable.gradientRadius = gradientBuilder.radius
        drawable.setGradientCenter(gradientBuilder.centerX, gradientBuilder.centerY)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            drawable.setPadding(paddingBuilder.left, paddingBuilder.top, paddingBuilder.right, paddingBuilder.bottom)
        }

        drawable.setStroke(strokeBuilder.width, strokeBuilder.color, strokeBuilder.dashWidth, strokeBuilder.dashGap)

        drawable.cornerRadii = floatArrayOf(
            cornersBuilder.topLeft, cornersBuilder.topLeft,
            cornersBuilder.topRight, cornersBuilder.topRight,
            cornersBuilder.bottomRight, cornersBuilder.bottomRight,
            cornersBuilder.bottomLeft, cornersBuilder.bottomLeft,
        )
        return drawable
    }

    class SizeBuilder {
        var width = 0
        var height = 0
    }

    class CornersBuilder {
        var topLeft = 0f
        var topRight = 0f
        var bottomLeft = 0f
        var bottomRight = 0f
    }

    class PaddingBuilder {
        var left = 0
        var top = 0
        var right = 0
        var bottom = 0
    }

    class StrokeBuilder {
        var width = 0
        var color = Color.TRANSPARENT
        private var dash = DashBuilder()
        var dashWidth by dash::width
        var dashGap by dash::gap

        fun dash(builder: DashBuilder.() -> Unit) {
            dash.builder()
        }

        class DashBuilder {
            var width = 0f
            var gap = 0f
        }
    }

    class GradientBuilder {
        private var color = ColorBuilder()
        var type = GradientType.LINEAR
        var radius = 0f
        var centerX = 0f
        var centerY = 0f
        var userLevel = false
        var endColor: Int? by color::end
        var centerColor: Int? by color::center
        var startColor: Int? by color::start

        val colors: IntArray get() = listOfNotNull(startColor, centerColor, endColor).toIntArray()

        fun color(color: Int) = color(color, color)

        fun color(start: Int, end: Int, center: Int? = null) {
            color.start = start
            color.center = center
            color.end = end
        }

        fun color(builder: ColorBuilder.() -> Unit) {
            color.builder()
        }

        class ColorBuilder {
            var start: Int? = null
            var center: Int? = null
            var end: Int? = null
        }
    }

}

val Int.dp: Int
    get() = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        this.toFloat(),
        Resources.getSystem().displayMetrics
    ).toInt()

val Float.dp: Float
    get() = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        this,
        Resources.getSystem().displayMetrics
    )